home *** CD-ROM | disk | FTP | other *** search
/ CU Amiga Super CD-ROM 18 / CU Amiga Magazine's Super CD-ROM 18 (1997)(EMAP Images)(GB)[!][issue 1998-01].iso / CUCD / Programming / ModemLink / Source / ModemLinkTask.c < prev    next >
C/C++ Source or Header  |  1997-10-24  |  14KB  |  484 lines

  1. /*
  2. ** NAME: ModemLinkTask.c
  3. ** DESC: This routine contains all the code for the built-in Stop & Wait
  4. **       protocol.  This is spawned by modemlink from the Link.c module.
  5. **       Other routines in this file are support routines for the protocol.
  6. **
  7. ** AUTHOR:        DATE:       DESCRIPTION:
  8. ** ~~~~~~~~~~~~~~ ~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  9. ** Mike Veroukis  06 Apr 1997 Created
  10. */
  11.  
  12.  
  13. #include <exec/errors.h>
  14. #include <exec/io.h>
  15. #include <exec/memory.h>
  16. #include <exec/ports.h>
  17. #include <exec/types.h>
  18. #include <devices/serial.h>
  19. #include <devices/timer.h>
  20. #include <dos/dosextens.h>
  21. #include <dos/dostags.h>
  22.  
  23. #include <proto/dos.h>
  24. #include <proto/exec.h>
  25.  
  26. #include <string.h>
  27. #include <stdio.h>
  28. #include <dos.h>
  29.  
  30. #include "ModemLinkTask.h"
  31. #include "Link.h"
  32. #include "ModemLinkAPI.h"
  33. #include "CRC.h"
  34. #include "DeviceStuff.h"
  35.  
  36. char ReadPacketNum(struct IOExtSer *SerReadIO)
  37. {
  38.   char PktLong = 0;
  39.  
  40.   if (SerReadIO) {
  41.     SerReadIO->IOSer.io_Command = CMD_READ;
  42.     SerReadIO->IOSer.io_Length = sizeof(char);
  43.     SerReadIO->IOSer.io_Data = (APTR)&PktLong;
  44.  
  45.     // To be changed to TimedIO() later on
  46.     DoIO((struct IORequest *) SerReadIO);
  47.   }
  48.  
  49.   return (PktLong);
  50. }
  51.  
  52. int ReadPacketWord(struct IOExtSer *SerReadIO)
  53. {
  54.   int PktWord = -1;
  55.  
  56.   if (SerReadIO) {
  57.     SerReadIO->IOSer.io_Command = CMD_READ;
  58.     SerReadIO->IOSer.io_Length = sizeof(int);
  59.     SerReadIO->IOSer.io_Data = (APTR)&PktWord;
  60.  
  61.     // To be changed to TimedIO() later on
  62.     DoIO((struct IORequest *) SerReadIO);
  63.   }
  64.  
  65.   return (PktWord);
  66. }
  67.  
  68. LONG ReadPacketLong(struct IOExtSer *SerReadIO)
  69. {
  70.   LONG PktLong = -1;
  71.  
  72.   if (SerReadIO) {
  73.     SerReadIO->IOSer.io_Command = CMD_READ;
  74.     SerReadIO->IOSer.io_Length = sizeof(LONG);
  75.     SerReadIO->IOSer.io_Data = (APTR)&PktLong;
  76.  
  77.     // To be changed to TimedIO() later on
  78.     DoIO((struct IORequest *) SerReadIO);
  79.   }
  80.  
  81.   return (PktLong);
  82. }
  83.  
  84. BYTE *ReadPacketData(struct IOExtSer *SerReadIO, LONG Length)
  85. {
  86.   BYTE *PktData = NULL;
  87.  
  88.   if (SerReadIO && Length > 0) {
  89.     if (PktData = (char *)AllocMem(Length, MEMF_PUBLIC)) {
  90.       SerReadIO->IOSer.io_Command = CMD_READ;
  91.       SerReadIO->IOSer.io_Length = Length;
  92.       SerReadIO->IOSer.io_Data = (APTR)PktData;
  93.  
  94.       // To be changed to TimedIO() later on
  95.       DoIO((struct IORequest *) SerReadIO);
  96.     }
  97.   }
  98.  
  99.   return (PktData);
  100. }
  101.  
  102. int ReadPacket(struct IOExtSer *SerIO, struct LinkPkt **Pkt, UBYTE CurPktNum)
  103. {
  104.   UBYTE PktNum;
  105.   ULONG CRC;
  106.   int err = 0;
  107.  
  108.   if (*Pkt = ML_AllocPkt()) {
  109.     PktNum = ReadPacketNum(SerIO);
  110.  
  111.     SerIO->IOSer.io_Command = CMD_READ;
  112.     SerIO->IOSer.io_Length = (ULONG)&((*Pkt)->Data) - (ULONG)&((*Pkt)->Length);
  113.     SerIO->IOSer.io_Data = &((*Pkt)->Length);
  114.     DoIO((struct IORequest *) SerIO);
  115.  
  116.     (*Pkt)->Data = ReadPacketData(SerIO, (*Pkt)->Length);
  117.  
  118.     if (PktNum != CurPktNum)
  119.       err = RPERR_PKTNUM;
  120.  
  121.     CRC = GetCRC((*Pkt)->Data, (*Pkt)->Length);
  122.  
  123.     if (CRC != (*Pkt)->CRC)
  124.       err = RPERR_PKTCRC;
  125.  
  126.     if (err) {
  127.       ML_FreePkt(*Pkt);
  128.     }
  129.   }
  130.   else
  131.     err = RPERR_NOPKT;
  132.  
  133.   return (err);
  134. }
  135.  
  136. void WritePacket(struct IOExtSer *SerIO, struct LinkPkt *Pkt, UBYTE CurPktNum)
  137. {
  138.   UBYTE buf[2];
  139.  
  140.   if (SerIO && Pkt) {
  141.     buf[0] = SOH;
  142.     buf[1] = CurPktNum;
  143.  
  144.     Pkt->CRC = GetCRC(Pkt->Data, Pkt->Length);
  145.  
  146.     SerIO->IOSer.io_Command = CMD_WRITE;
  147.     SerIO->IOSer.io_Length = 2 * sizeof(char);
  148.     SerIO->IOSer.io_Data = (APTR)buf;
  149.     DoIO((struct IORequest *) SerIO);
  150.  
  151.     SerIO->IOSer.io_Command = CMD_WRITE;
  152.     SerIO->IOSer.io_Length = (ULONG)&(Pkt->Data) - (ULONG)&(Pkt->Length);
  153.     SerIO->IOSer.io_Data = &(Pkt->Length);
  154.     DoIO((struct IORequest *) SerIO);
  155.  
  156.  
  157.     SerIO->IOSer.io_Command = CMD_WRITE;
  158.     SerIO->IOSer.io_Length = Pkt->Length;
  159.     SerIO->IOSer.io_Data = (APTR)Pkt->Data;
  160.     DoIO((struct IORequest *) SerIO);
  161.   }
  162. }
  163.  
  164. void SendCode(struct IOExtSer *SerWriteIO,  BYTE Code, BYTE CurPktNum)
  165. {
  166.   UBYTE buf[2];
  167.  
  168.   if (SerWriteIO) {
  169.     buf[0] = Code;
  170.     buf[1] = CurPktNum;
  171.  
  172.     SerWriteIO->IOSer.io_Command = CMD_WRITE;
  173.     SerWriteIO->IOSer.io_Data = (APTR)buf;
  174.     if (CurPktNum < 0)
  175.       SerWriteIO->IOSer.io_Length = 1;
  176.     else
  177.       SerWriteIO->IOSer.io_Length = 2;
  178.  
  179.     // To be changed to TimedIO() later on
  180.     DoIO((struct IORequest *) SerWriteIO);
  181.   }
  182. }
  183.  
  184. void ResetTimer(struct timerequest *TimerIO)
  185. {
  186.   DoAbortIO((struct IORequest *) TimerIO);
  187.  
  188.   TimerIO->tr_node.io_Command = TR_ADDREQUEST;
  189.   TimerIO->tr_time.tv_secs = 3;
  190.   TimerIO->tr_time.tv_micro = 0;
  191.   SendIO((struct IORequest *) TimerIO);
  192. }
  193.  
  194.  
  195. void SetTimer(struct timerequest *TimerIO)
  196. {
  197.   TimerIO->tr_node.io_Command = TR_ADDREQUEST;
  198.   TimerIO->tr_time.tv_secs = 3;
  199.   TimerIO->tr_time.tv_micro = 0;
  200.   SendIO((struct IORequest *) TimerIO);
  201. }
  202.  
  203. void __saveds __asm AckTask(register __d0 ULONG Len, register __a0 char *PortName)
  204. {
  205.   struct IOExtSer *SerIO;          // points to the SerIO req. that's passed to us
  206.   struct IOExtSer *SerWriteIO;     // is used exclusively for writing to serial device
  207.   struct IOExtSer *SerReadIO;      // is used exclusively for reading from serial device
  208.   struct timerequest *TimerIO = NULL; // used for TIMEOUTs when waiting for ACK
  209.   struct MsgPort *SerWriteMP;      // message port for SerWriteIO
  210.   struct MsgPort *SerReadMP;       // message port for SerReadIO
  211.   struct MsgPort *TimerMP = NULL;  // message port for TimerIO
  212.   struct MsgPort *LinkMP;          // we get all our IO reqs through this port
  213.   struct LinkPkt OutPkt;           // contents of packet to write to serial device
  214.   struct LinkPkt *InPkt = NULL;    // points to packet just read from serial device
  215.   struct List InPktList;           // list of packets read, but not yet sent to user
  216.   struct IOExtLink *ReadReq = NULL;   // current user read IO request structure
  217.   struct IOExtLink *WriteReq = NULL;  // current user write IO request structure
  218.   struct IOExtLink *Req;           // next read/write IO request structure
  219.  
  220.   ULONG SerWriteBit, SerReadBit;   // signal bits for serial read/write
  221.   ULONG TimerBit, PktBit;          // signal bits for timer and new LinkIO packet
  222.   ULONG WaitMask, Sig = 0;         // Mask for Wait()
  223.  
  224.   int err;
  225.  
  226.   UBYTE CurInPktNum = 0;
  227.   UBYTE CurOutPktNum = 0;
  228.   UBYTE WaitACK = 0;
  229.   UBYTE WaitPacket = 0;
  230.   UBYTE ReadyToSend = 1;
  231.   UBYTE PktType;
  232.  
  233.  
  234.   NewList(&InPktList);
  235.  
  236.   if (LinkMP = CreateMsgPort()) {
  237.     LinkMP->mp_Node.ln_Name = PortName;
  238.     LinkMP->mp_Node.ln_Pri = 0;
  239.     AddPort(LinkMP);
  240.  
  241.     WaitPort(LinkMP);
  242.     Req = (struct IOExtLink *)GetMsg(LinkMP);
  243.     SerIO = (struct IOExtSer *)Req->IOLink.io_Data;
  244.  
  245.     if (Req->IOLink.io_Device) {
  246.       putreg(REG_A6, (long)Req->IOLink.io_Device); 
  247.       geta4();
  248.     }
  249.  
  250.     ReplyMsg((struct Message *)Req);
  251.  
  252.     if (OpenTimerDevice(&TimerMP, &TimerIO)) {
  253.  
  254.       Req = NULL;
  255.  
  256.       if (CloneIO((struct IORequest *)SerIO, &SerReadMP, (struct IORequest **)&SerReadIO)) {
  257.         if (CloneIO((struct IORequest *)SerIO, &SerWriteMP, (struct IORequest **)&SerWriteIO)) {
  258.  
  259.           SerWriteBit = 1 << SerWriteMP->mp_SigBit;
  260.           SerReadBit = 1 << SerReadMP->mp_SigBit;
  261.           TimerBit = 1 << TimerMP->mp_SigBit;
  262.           PktBit = 1 << LinkMP->mp_SigBit;
  263.  
  264.           WaitMask = SerWriteBit | SerReadBit | TimerBit | PktBit | SIGBREAKF_CTRL_C | SIGBREAKF_CTRL_D | SIGBREAKF_CTRL_E;
  265.  
  266.           SerReadIO->IOSer.io_Command = CMD_READ;
  267.           SerReadIO->IOSer.io_Length = ID_LENGTH;
  268.           SerReadIO->IOSer.io_Data = (APTR)&PktType;
  269.           SendIO((struct IORequest *) SerReadIO);
  270.  
  271.           while (!(Sig & SIGBREAKF_CTRL_C)) {
  272.             Sig = Wait(WaitMask);
  273.  
  274.             if (WaitACK && CheckIO((struct IORequest *) TimerIO)) {
  275.               WaitIO((struct IORequest *) TimerIO);
  276.               WritePacket(SerWriteIO, &OutPkt, CurOutPktNum);
  277.               WaitACK = 1;
  278.               ResetTimer(TimerIO);
  279.             }
  280.  
  281.             if (CheckIO((struct IORequest *) SerReadIO)) {
  282.               WaitIO((struct IORequest *) SerReadIO);
  283.               // remember, PktType is set by io_Data above
  284.               switch (PktType) {
  285.                 case SOH:
  286.                   err = ReadPacket(SerReadIO, &InPkt, CurInPktNum);
  287.                   if (!err) {
  288.                     AddTail(&InPktList, (struct Node *)InPkt);
  289.                     SendCode(SerWriteIO, ACK, CurInPktNum);
  290.                     CurInPktNum ^= 1;
  291.                   }
  292.                   else if (err == RPERR_PKTNUM) 
  293.                     SendCode(SerWriteIO, ACK, CurInPktNum ^ 1);
  294.                   else
  295.                     SendCode(SerWriteIO, GACK, -1);
  296.  
  297.                   if (WaitACK)
  298.                     ResetTimer(TimerIO);
  299.  
  300.                   break;
  301.                 case ACK:
  302.                   if (CurOutPktNum == ReadPacketNum(SerReadIO)) {
  303.                     DoAbortIO((struct IORequest *) TimerIO);
  304.                     CurOutPktNum ^= 1;
  305.                     ReadyToSend = 1;
  306.                     ML_ReplyMsg(WriteReq);
  307.                     WriteReq = NULL;
  308.                     WaitACK = 0;
  309.                   }
  310.                   break;
  311.                 case GACK:
  312.                   WritePacket(SerWriteIO, &OutPkt, CurOutPktNum);
  313.                   WaitACK = 1;
  314.                   ResetTimer(TimerIO);
  315.                   break;
  316.                 case ENQ:
  317.                   SendCode(SerWriteIO, ACK, -1);
  318.                   break;
  319.                 case CAN:
  320.                   Signal(FindTask(NULL), SIGBREAKF_CTRL_C);
  321.                   break;
  322.               }
  323.               SerReadIO->IOSer.io_Command = CMD_READ;
  324.               SerReadIO->IOSer.io_Length = ID_LENGTH;
  325.               SerReadIO->IOSer.io_Data = (APTR)&PktType;
  326.               SendIO((struct IORequest *) SerReadIO);
  327.             }
  328.  
  329.             /*
  330.             ** Check for aborted requests...
  331.             */
  332.             if (Req && Req->IOLink.io_Error == IOERR_ABORTED) {
  333.               ML_ReplyMsg(Req);
  334.               Req = NULL;
  335.             }
  336.  
  337.             if (ReadReq && ReadReq->IOLink.io_Error == IOERR_ABORTED) {
  338.               ML_ReplyMsg(ReadReq);
  339.               ReadReq = NULL;
  340.               WaitPacket = 0;
  341.             }
  342.  
  343.             /*
  344.             ** Read incomming packets
  345.             */
  346.             if (!Req) {
  347.               Req = ML_GetMsg(LinkMP, ML_PIPE1);
  348.             }
  349.  
  350.             if (Req && !ReadReq &&
  351.                 (Req->IOLink.io_Command == MLCMD_READ ||
  352.                 Req->IOLink.io_Command == CMD_READ)) {
  353.               ReadReq = Req;
  354.               Req = ML_GetMsg(LinkMP, ML_PIPE1);
  355.               WaitPacket = 1;
  356.             }
  357.  
  358.             if (!WriteReq &&
  359.                 (Req && Req->IOLink.io_Command == MLCMD_WRITE ||
  360.                 Req && Req->IOLink.io_Command == CMD_WRITE)) {
  361.               WriteReq = Req;
  362.               Req = NULL;
  363.  
  364.               if (Req && Req->IOLink.io_Command == MLCMD_WRITE)
  365.                 CopyMem(WriteReq->IOLink.io_Data, &OutPkt, sizeof(struct LinkPkt));
  366.               else {
  367.                 if (WriteReq->IOLink.io_Length < 0)
  368.                   OutPkt.Length = strlen(WriteReq->IOLink.io_Data);
  369.                 else
  370.                   OutPkt.Length = WriteReq->IOLink.io_Length;
  371.  
  372.                 OutPkt.Data = WriteReq->IOLink.io_Data;
  373.               }
  374.             }
  375.  
  376.             /*
  377.             ** If ready to send Pkt and out going packet exists, send it.
  378.             */
  379.             if (ReadyToSend && WriteReq) {
  380.               WriteReq->Flags = WriteReq->Flags | ML_PIPE2;
  381.               WritePacket(SerWriteIO, &OutPkt, CurOutPktNum);
  382.  
  383.               if (WaitACK)
  384.                 ResetTimer(TimerIO);
  385.               else
  386.                 SetTimer(TimerIO);
  387.  
  388.               WaitACK = 1;
  389.               ReadyToSend = 0;
  390.             }
  391.  
  392.             /*
  393.             ** If incomming Pkt is queued and we have Read req, reply it.
  394.             */
  395.             if (ReadReq && WaitPacket && !(IsListEmpty(&InPktList))) {
  396.               InPkt = (struct LinkPkt *)RemHead(&InPktList);
  397.  
  398.               if (ReadReq->IOLink.io_Command == CMD_READ) {
  399.                 ReadReq->IOLink.io_Data = InPkt->Data;
  400.                 ReadReq->IOLink.io_Length = InPkt->Length;
  401.                 FreeMem(InPkt, sizeof (struct LinkPkt));
  402.               }
  403.               else
  404.                 ReadReq->IOLink.io_Data = InPkt;
  405.  
  406.               ML_ReplyMsg(ReadReq);
  407.               InPkt = NULL;
  408.               ReadReq = NULL;
  409.               WaitPacket = 0;
  410.             }
  411.  
  412.             /*
  413.             ** Check CTRL-C -- shut down if CTRL-C detected.
  414.             */
  415.             if (Sig & SIGBREAKF_CTRL_C) {
  416.               if (WaitACK)
  417.                 DoAbortIO((struct IORequest *) TimerIO);
  418.  
  419.               SendCode(SerWriteIO, CAN, EOT);
  420.  
  421.               if (WriteReq) {
  422.                 WriteReq->IOLink.io_Error = IOERR_ABORTED;
  423.                 ML_ReplyMsg(WriteReq);
  424.               }
  425.  
  426.               if (ReadReq) {
  427.                 ReadReq->IOLink.io_Error = IOERR_ABORTED;
  428.                 ML_ReplyMsg(ReadReq);
  429.               }
  430.             }
  431.  
  432.             /*
  433.             ** ^C or ^E arrives
  434.             ** this continues the shut down process from above and since the
  435.             ** CLEAR command issued by ^E does the same thing, they share
  436.             ** the same code:
  437.             ** deallocate all buffered incomming packets
  438.             */
  439.             if ((Sig & SIGBREAKF_CTRL_C) || (Sig & SIGBREAKF_CTRL_E)) {
  440.               while (InPkt = (struct LinkPkt *)RemHead(&InPktList)) {
  441.                 FreeMem(InPkt->Data, InPkt->Length);
  442.                 FreeMem(InPkt, sizeof(struct LinkPkt));
  443.               }
  444.             }
  445.  
  446.             SerWriteIO->IOSer.io_Command = SDCMD_QUERY;
  447.             DoIO((struct IORequest *) SerWriteIO);
  448.  
  449.             if (SerWriteIO->io_Status & (1 << 5))
  450.               Signal(FindTask(NULL), SIGBREAKF_CTRL_C);
  451.           }
  452.  
  453.           DeleteIO_MP(SerWriteMP, (struct IORequest *) SerWriteIO);
  454.         }
  455.  
  456.         DoAbortIO((struct IORequest *) SerReadIO);
  457.         DeleteIO_MP(SerReadMP, (struct IORequest *) SerReadIO);
  458.       }
  459.  
  460.       if (WaitACK)
  461.         DoAbortIO((struct IORequest *)TimerIO);
  462.       SafeCloseDevice(TimerMP, (struct IORequest *)TimerIO);
  463.  
  464.     }
  465.  
  466.     /*
  467.     ** remove all queued IO requests and remove MsgPort as well
  468.     */
  469.     Forbid();
  470.     if (!Req) 
  471.       Req = ML_GetMsg(LinkMP, ML_PIPE1);
  472.  
  473.     while (Req) {
  474.       Req->IOLink.io_Error = IOERR_ABORTED;
  475.       ML_ReplyMsg(Req);
  476.       Req = ML_GetMsg(LinkMP, ML_PIPE1);
  477.     }
  478.  
  479.     RemPort(LinkMP);
  480.     DeleteMsgPort(LinkMP);
  481.     Permit();
  482.   }
  483. }
  484.